package wx

import (
	"context"
	"encoding/json"
	"errors"
	"log/slog"
	"net/url"
	"sort"
	"strings"
	"time"

	"gitee.com/gxcc/go-utils/utils"

	"gitee.com/gxcc/go-thirds/cache"
)

// WxghSvc 微信公众号
type WxghSvc struct {
	AppId     string
	AppSecret string
}

type WxghUserAuthResult struct {
	Errcode      int    `json:"errcode"`
	Errmsg       string `json:"errmsg"`
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	OpenId       string `json:"openid"`
	UnionId      string `json:"unionid"`
	Scope        string `json:"scope"`
}

// GetAuthAccessToken 获取授权信息
func (w *WxghSvc) GetAuthAccessToken(code string) (WxghUserAuthResult, error) {
	reqUrl := "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + w.AppId + "&secret=" + w.AppSecret +
		"&code=" + code + "&grant_type=authorization_code"
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return WxghUserAuthResult{}, err
	}

	var authResult WxghUserAuthResult
	if err := json.Unmarshal(res.Body, &authResult); err != nil {
		slog.Error(err.Error())
		return WxghUserAuthResult{}, err
	}
	if authResult.Errcode != 0 {
		return WxghUserAuthResult{}, errors.New("获取用户授权失败：" + authResult.Errmsg)
	}
	return authResult, nil
}

// GetAuthUserInfo 获取授权的用户信息
func (w *WxghSvc) GetAuthUserInfo(accessToken string, openid string) (WxUser, error) {
	reqUrl := "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN"
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return WxUser{}, err
	}

	var wxUser WxUser
	if err := json.Unmarshal(res.Body, &wxUser); err != nil {
		slog.Error(err.Error())
		return WxUser{}, err
	}
	if len(wxUser.Openid) == 0 {
		return WxUser{}, errors.New("获取用户授权失败：" + string(res.Body))
	}
	return wxUser, nil
}

// 刷新AccessToken
func (w *WxghSvc) reloadAccessToken() (string, error) {
	reqUrl := "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + w.AppId + "&secret=" + w.AppSecret
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Info struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int    `json:"expires_in"`
	}
	var info Info
	if err := json.Unmarshal(res.Body, &info); err != nil {
		slog.Error(err.Error())
		return "", err
	}
	if len(info.AccessToken) == 0 {
		return "", errors.New("获取微信公众平台accessToken失败，返回结果：" + string(res.Body))
	}

	// 缓存到redis中
	var ctx = context.Background()
	var cacheKey = "wxgh_access_token_" + w.AppId
	cache.RedisClient.Set(ctx, cacheKey, info.AccessToken, time.Duration(info.ExpiresIn-60)*time.Second)

	slog.Debug("reloadAccessToken", "accessToken ", info.AccessToken)
	return info.AccessToken, nil
}

// GetAccessToken 获取AccessToken
func (w *WxghSvc) GetAccessToken() (string, error) {
	var ctx = context.Background()
	var cacheKey = "wxgh_access_token_" + w.AppId
	accessToken, err := cache.RedisClient.Get(ctx, cacheKey).Result()
	if err != nil || len(accessToken) == 0 {
		accessToken, err := w.reloadAccessToken()
		if err != nil {
			slog.Error(err.Error())
			return "", err
		} else {
			return accessToken, nil
		}
	} else {
		return accessToken, nil
	}
}

// 刷新JsApiTicket
func (w *WxghSvc) reloadJsApiTicket() (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi"
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}
	type Info struct {
		Ticket    string `json:"ticket"`
		ExpiresIn int    `json:"expires_in"`
	}
	var info Info
	if err := json.Unmarshal(res.Body, &info); err != nil {
		slog.Error(err.Error())
		return "", err
	}
	if len(info.Ticket) == 0 {
		return "", errors.New("获取微信公众平台JsApiTicket失败，返回结果：" + string(res.Body))
	}

	// 缓存到redis中
	var ctx = context.Background()
	var cacheKey = "wxgh_js_api_ticket_" + w.AppId
	cache.RedisClient.Set(ctx, cacheKey, info.Ticket, time.Duration(info.ExpiresIn-60)*time.Second)

	slog.Debug("reloadJsApiTicket", "jsApiTicket", info.Ticket)
	return info.Ticket, nil
}

// GetJsApiTicket 获取JsApiTicket
func (w *WxghSvc) GetJsApiTicket() (string, error) {
	var ctx = context.Background()
	var cacheKey = "wxgh_js_api_ticket_" + w.AppId
	jsApiTicket, err := cache.RedisClient.Get(ctx, cacheKey).Result()
	if err != nil || len(jsApiTicket) == 0 {
		ticket, err := w.reloadJsApiTicket()
		if err != nil {
			slog.Error(err.Error())
			return "", err
		} else {
			return ticket, nil
		}
	} else {
		return jsApiTicket, nil
	}
}

// GenJsSdkSign 获取JsSdk签名
func (w *WxghSvc) GenJsSdkSign(timestamp string, nonceStr string, url string) string {
	jsApiTicket, _ := w.GetJsApiTicket()
	str := "jsapi_ticket=" + jsApiTicket +
		"&noncestr=" + nonceStr +
		"&timestamp=" + timestamp +
		"&url=" + url
	slog.Debug("genJsSdkSign", "originalStr", str)
	return utils.SHA1(str)
}

// 刷新CardApiTicket
func (w *WxghSvc) reloadCardApiTicket() (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=wx_card"
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Info struct {
		Ticket    string `json:"ticket"`
		ExpiresIn int    `json:"expires_in"`
	}
	var info Info
	if err := json.Unmarshal(res.Body, &info); err != nil {
		slog.Error(err.Error())
		return "", err
	}
	if len(info.Ticket) == 0 {
		return "", errors.New("获取微信公众平台CardApiTicket失败，返回结果：" + string(res.Body))
	}

	// 缓存到redis中
	var ctx = context.Background()
	var cacheKey = "wxgh_card_api_ticket_" + w.AppId
	cache.RedisClient.Set(ctx, cacheKey, info.Ticket, time.Duration(info.ExpiresIn-60)*time.Second)

	slog.Debug("reloadCardApiTicket", "cardApiTicket", info.Ticket)
	return info.Ticket, nil
}

// GetCardApiTicket 获取CardApiTicket
func (w *WxghSvc) GetCardApiTicket() (string, error) {
	var ctx = context.Background()
	var cacheKey = "wxgh_card_api_ticket_" + w.AppId
	jsApiTicket, err := cache.RedisClient.Get(ctx, cacheKey).Result()
	if err != nil || len(jsApiTicket) == 0 {
		ticket, err := w.reloadCardApiTicket()
		if err != nil {
			slog.Error(err.Error())
			return "", err
		} else {
			return ticket, nil
		}
	} else {
		return jsApiTicket, nil
	}
}

// GenCardSign 获取card签名
func (w *WxghSvc) GenCardSign(cardType string, timestamp string, nonceStr string) string {
	cardApiTicket, _ := w.GetCardApiTicket()
	slog.Debug("cardApiTicket:" + cardApiTicket)
	var slice = []string{w.AppId, cardApiTicket, cardType, timestamp, nonceStr}
	sort.Strings(slice)
	str := slice[0] + slice[1] + slice[2] + slice[3] + slice[4]
	slog.Debug("genCardSign", "originalStr", str)
	return utils.SHA1(str)
}

// GetUserInfo 获取用户信息
func (w *WxghSvc) GetUserInfo(openid string) (WxUser, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return WxUser{}, err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN"
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return WxUser{}, err
	}

	var wxUser WxUser
	if err := json.Unmarshal(res.Body, &wxUser); err != nil {
		slog.Error(err.Error())
		return WxUser{}, err
	}
	if len(wxUser.Openid) == 0 {
		return WxUser{}, errors.New("获取用户信息失败，返回结果：" + string(res.Body))
	}
	return wxUser, nil
}

// SendTplMsg 发送模版消息
func (w *WxghSvc) SendTplMsg(openid string, tplId string, clickUrl string, content map[string]string) error {
	if len(openid) <= 0 {
		slog.Warn("微信模版消息无法发送, err: openid is empty")
		return errors.New("openid为空，无法发送模板消息")
	}
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken

	dataMap := map[string]any{}
	for key := range content {
		dataMap[key] = map[string]string{
			"value": content[key],
		}
	}

	bodyMap := map[string]any{
		"touser":      openid,
		"template_id": tplId,
		"url":         clickUrl,
		"data":        dataMap,
	}

	reqBody, _ := json.Marshal(bodyMap)
	res, err := utils.HttpPost(reqUrl, nil, reqBody)
	if err != nil {
		slog.Error(err.Error())
		return err
	}

	var result ErrorResult
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return err
	}
	if result.Errcode == 0 {
		return nil
	} else {
		slog.Error("发送模版消息失败，err：" + result.Errmsg)
		return errors.New(result.Errmsg)
	}
}

// SendCustomMsg 发送客服消息
func (w *WxghSvc) SendCustomMsg(msg map[string]any) error {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/message/custom/send?" + values.Encode()

	data, _ := json.Marshal(msg)
	res, err := utils.HttpPost(reqUrl, nil, data)
	if err != nil {
		slog.Error(err.Error())
		return err
	}
	slog.Debug(string(res.Body))

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return err
	}
	if result.Errcode != 0 {
		return errors.New("发送客服消息失败，返回结果：" + string(res.Body))
	}

	return nil
}

// GenQRCodeTemp 生成带参数的二维码(临时二维码)
func (w *WxghSvc) GenQRCodeTemp(scene string, expireSeconds int64) (string, string, error) {
	if len(scene) > 64 {
		return "", "", errors.New("场景值长度限制为1-64")
	}

	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", "", err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/qrcode/create?" + values.Encode()

	if expireSeconds == 0 {
		// 默认有效期30天(最大值)
		expireSeconds = 2592000
	}
	var params = map[string]interface{}{
		"expire_seconds": expireSeconds,
		"action_name":    "QR_STR_SCENE",
		"action_info": map[string]interface{}{
			"scene": map[string]string{
				"scene_str": scene,
			},
		},
	}
	data, _ := json.Marshal(params)

	res, err := utils.HttpPost(reqUrl, nil, data)
	if err != nil {
		slog.Error(err.Error())
		return "", "", err
	}

	slog.Debug(string(res.Body))

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Ticket  string `json:"ticket"`
	}

	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return "", "", err
	}
	if result.Errcode != 0 {
		return "", "", errors.New("生成二维码失败，返回结果：" + string(res.Body))
	}

	qrcodeUrl := "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + result.Ticket
	return result.Ticket, qrcodeUrl, nil
}

// GenQRCodePerm 生成带参数的二维码(永久二维码)
func (w *WxghSvc) GenQRCodePerm(scene string) (string, string, error) {
	if len(scene) > 64 {
		return "", "", errors.New("场景值长度限制为1-64")
	}

	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", "", err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/qrcode/create?" + values.Encode()

	var params = map[string]interface{}{
		"action_name": "QR_LIMIT_STR_SCENE",
		"action_info": map[string]interface{}{
			"scene": map[string]string{
				"scene_str": scene,
			},
		},
	}
	data, _ := json.Marshal(params)

	res, err := utils.HttpPost(reqUrl, nil, data)
	if err != nil {
		slog.Error(err.Error())
		return "", "", err
	}

	slog.Debug(string(res.Body))

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Ticket  string `json:"ticket"`
	}

	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return "", "", err
	}
	if result.Errcode != 0 {
		return "", "", errors.New("生成二维码失败，返回结果：" + string(res.Body))
	}

	qrcodeUrl := "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + result.Ticket
	return result.Ticket, qrcodeUrl, nil
}

// GetMenu 获取菜单
func (w *WxghSvc) GetMenu() (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=" + accessToken
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	var result ErrorResult
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return "", err
	}
	if result.Errcode == 0 {
		return string(res.Body), nil
	} else {
		return "", errors.New(result.Errmsg)
	}
}

// SaveMenu 保存菜单
func (w *WxghSvc) SaveMenu(menu string) error {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return err
	}
	reqUrl := "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken
	data := []byte(menu)
	res, err := utils.HttpPost(reqUrl, nil, data)
	if err != nil {
		slog.Error(err.Error())
		return err
	}

	var result ErrorResult
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return err
	}
	if result.Errcode == 0 {
		return nil
	} else {
		return errors.New(result.Errmsg)
	}
}

// AddMaterial 新增永久素材
// fileType: 媒体文件类型，分别有图片（image）、语音（voice）、视频（video），缩略图（thumb）
func (w *WxghSvc) AddMaterial(fileType string, filePath string) (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	values.Add("type", fileType)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/material/add_material?" + values.Encode()

	res, err := utils.HttpPostMultipartForm(reqUrl, nil, nil, map[string]string{
		"media": filePath,
	})
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		MediaId string `json:"media_id"`
		Url     string `json:"url"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		slog.Error("返回结果：", string(res.Body))
		return "", err
	}

	if result.Errcode != 0 {
		return "", errors.New("上传临时素材失败，返回结果：" + string(res.Body))
	}

	return result.MediaId, nil
}

// GetMaterial 获取永久素材
func (w *WxghSvc) GetMaterial(mediaId string) ([]byte, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return nil, err
	}
	reqUrl := "http://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" + accessToken + "&media_id=" + mediaId
	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return nil, err
	}

	resContentType := res.Header.Get("Content-Type")
	if strings.Contains(resContentType, "text") || strings.Contains(resContentType, "json") {
		var result ErrorResult
		if err := json.Unmarshal(res.Body, &result); err != nil {
			slog.Error(err.Error())
			return nil, err
		}
		if result.Errcode != 0 {
			return nil, errors.New(result.Errmsg)
		}
	}
	return res.Body, nil
}

// UploadTempMedia 新增临时素材
// fileType: 媒体文件类型，分别有图片（image）、语音（voice）、视频（video），普通文件（file）
func (w *WxghSvc) UploadTempMedia(fileType string, filePath string) (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	values.Add("type", fileType)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/media/upload?" + values.Encode()

	res, err := utils.HttpPostMultipartForm(reqUrl, nil, nil, map[string]string{
		"media": filePath,
	})
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		MediaId string `json:"media_id"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		slog.Error("返回结果：", string(res.Body))
		return "", err
	}

	if result.Errcode != 0 {
		return "", errors.New("上传临时素材失败，返回结果：" + string(res.Body))
	}

	return result.MediaId, nil
}

// GetTempMedia 获取临时素材
func (w *WxghSvc) GetTempMedia(mediaId string) (*utils.HttpResult, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return nil, err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	values.Add("media_id", mediaId)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/media/get?" + values.Encode()

	res, err := utils.HttpGet(reqUrl, nil)
	if err != nil {
		slog.Error(err.Error())
		return nil, err
	}

	if strings.Contains(res.Header.Get("Content-Type"), "application/json") {
		type Result struct {
			Errcode int    `json:"errcode"`
			Errmsg  string `json:"errmsg"`
		}
		var result Result
		if err := json.Unmarshal(res.Body, &result); err != nil {
			slog.Error(err.Error())
			return nil, err
		}
		return nil, errors.New("获取临时素材失败：" + result.Errmsg)
	}

	return res, nil
}

// 上传图文消息内的图片获取URL
func (w *WxghSvc) uploadImg(fileType string, filePath string) (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}

	var values = url.Values{}
	values.Add("access_token", accessToken)
	values.Add("type", fileType)
	reqUrl := "https://api.weixin.qq.com/cgi-bin/media/uploadimg?" + values.Encode()

	res, err := utils.HttpPostMultipartForm(reqUrl, nil, nil, map[string]string{
		"media": filePath,
	})
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Url     string `json:"url"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error(), "respBody", string(res.Body))
		return "", err
	}

	if result.Errcode != 0 {
		return "", errors.New("上传图片失败，返回结果：" + string(res.Body))
	}

	return result.Url, nil
}

// CheckCardCode 查询卡券是否可以核销
func (w *WxghSvc) CheckCardCode(cardId string, code string) (bool, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return false, err
	}
	reqUrl := "https://api.weixin.qq.com/card/code/get?access_token=" + accessToken

	dataMap := map[string]any{
		"card_id":       cardId,
		"code":          code,
		"check_consume": true,
	}

	reqBody, _ := json.Marshal(dataMap)
	res, err := utils.HttpPost(reqUrl, nil, reqBody)
	if err != nil {
		slog.Error(err.Error())
		return false, err
	}

	type Result struct {
		Errcode        int    `json:"errcode"`
		Errmsg         string `json:"errmsg"`
		CanConsume     bool   `json:"can_consume"`
		UserCardStatus string `json:"user_card_status"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return false, err
	}
	if result.Errcode == 0 {
		return result.CanConsume, nil
	} else {
		slog.Error("查询卡券失败，err：" + result.Errmsg)
		return false, errors.New(result.Errmsg)
	}
}

// ConsumeCardCode 核销卡券code
func (w *WxghSvc) ConsumeCardCode(cardId string, code string) error {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return err
	}
	reqUrl := "https://api.weixin.qq.com/card/code/consume?access_token=" + accessToken

	dataMap := map[string]any{
		"card_id": cardId,
		"code":    code,
	}

	reqBody, _ := json.Marshal(dataMap)
	res, err := utils.HttpPost(reqUrl, nil, reqBody)
	if err != nil {
		slog.Error(err.Error())
		return err
	}

	var result ErrorResult
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return err
	}
	if result.Errcode == 0 {
		return nil
	} else {
		slog.Error("核销卡券失败，err：" + result.Errmsg)
		return errors.New(result.Errmsg)
	}
}

// GetCard 获取卡券详情
func (w *WxghSvc) GetCard(cardId string) (WxCard, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return WxCard{}, err
	}
	reqUrl := "https://api.weixin.qq.com/card/get?access_token=" + accessToken

	dataMap := map[string]any{
		"card_id": cardId,
	}

	reqBody, _ := json.Marshal(dataMap)
	res, err := utils.HttpPost(reqUrl, nil, reqBody)
	if err != nil {
		slog.Error(err.Error())
		return WxCard{}, err
	}

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Card    WxCard `json:"card"`
	}
	slog.Debug("wx card detail:\n" + string(res.Body))
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return WxCard{}, err
	}

	if result.Errcode == 0 {
		result.Card.ReduceCost = result.Card.Cash.ReduceCost
		result.Card.LeastCost = result.Card.Cash.LeastCost
		return result.Card, nil
	} else {
		slog.Error("获取卡券详情失败，err：" + result.Errmsg)
		return WxCard{}, errors.New(result.Errmsg)
	}
}

// DecryptCardCode 解码卡券code
func (w *WxghSvc) DecryptCardCode(encryptCode string) (string, error) {
	accessToken, err := w.GetAccessToken()
	if err != nil {
		return "", err
	}
	reqUrl := "https://api.weixin.qq.com/card/code/decrypt?access_token=" + accessToken

	dataMap := map[string]any{
		"encrypt_code": encryptCode,
	}

	reqBody, _ := json.Marshal(dataMap)
	res, err := utils.HttpPost(reqUrl, nil, reqBody)
	if err != nil {
		slog.Error(err.Error())
		return "", err
	}

	type Result struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Code    string `json:"code"`
	}
	var result Result
	if err := json.Unmarshal(res.Body, &result); err != nil {
		slog.Error(err.Error())
		return "", err
	}

	if result.Errcode == 0 {
		return result.Code, nil
	} else {
		slog.Error("解码卡券code失败，err：" + result.Errmsg)
		return "", errors.New(result.Errmsg)
	}
}
